#ifndef DECODER_FLAC_FRAMES_H_
#define DECODER_FLAC_FRAMES_H_

#include <nds.h>
#include "decoder_flac_metadata.h"
#include "debug.h"


class FLACFrame {
public:
	void init(AudioReader *ar, FLACstreaminfo *sinfo);
	bool prepare();
	bool playerCall(int16_t *bufferL, int16_t *bufferR, uint32_t samples, uint32_t *count);

private:
	bool flag;
	bool nextHeaderOk;
	bool nextSub0ok;
	bool nextSub1ok;
	bool nextOk;
	uint16_t samplesLeft;

	struct Frame
	{
		struct Header
		{
			FLACstreaminfo *sinfo;
			AudioReader *reader;

			bool isVBS; // variable block size
			uint16_t blockSize;
			uint32_t sampleRate;
			uint8_t  channels;
			uint8_t  sampleSize;
			uint64_t number; // sample or frame number
			uint8_t  crc8;

			bool read();
		} header;

		struct Subframe
		{
			AudioReader *reader;
			bool isHeaderRead;

			int32_t samples[4096];
			uint16_t samplesRead;
			uint8_t order;
			uint8_t wasted;

			enum Type {
				FLAC_SUBFRAME_CONSTANT,
				FLAC_SUBFRAME_VERBATIM,
				FLAC_SUBFRAME_FIXED,
				FLAC_SUBFRAME_LPC
			} type;

			struct Lpc
			{
				uint8_t precision;
				uint8_t shift;
				int32_t vals[32];
			} lpc;

			struct Residual
			{
				bool isRice2;
				uint32_t ricePartitionsLeft;
				uint16_t riceOrder;
				uint16_t riceRead;
				struct RicePartition
				{
					uint16_t left;
					uint8_t parameter;
					bool encoded;
				} partition;
			} residual;

			bool readHeader();
			bool readConstant(const uint8_t _samplesize);
			bool readVerbatim(const uint8_t _samplesize, const uint16_t _blocksize);
			bool readFixed(const uint8_t _samplesize);
			bool readLpc(const uint8_t _samplesize);
			bool readResidualInit();
			bool readResidualRice(const uint16_t _blocksize);
			void restoreSignal(const uint16_t _blocksize);
			int playerCall(const uint8_t _samplesize, const uint16_t _blocksize);
		} subframes[2];

		struct Footer
		{
			AudioReader *reader;

			uint16_t crc16;
			bool read();
		} footer;

		void jointRestore();
	} frames[2];

};

#endif /* DECODER_FLAC_FRAMES_H_ */
